<template>
  <div class="home">
    <my-header></my-header>
    <!--标题-->
    <div class="top">
      <h1>一键Token</h1>
      <button class="top-button" @click="queryRecord">
        <img src="../assets/img/icon_record_white.png" alt="发行记录">
        发行记录
      </button>
    </div>
    <!--表单-->
    <div class="center">
      <ul>
        <li class="list-item">
          <img class="require" src="../assets/img/icon_require.png" alt>
          <div class="list-item-c">
            <div class="label">区块链名称</div>
            <div class="content">
              <input type="text" readonly v-model="confirmForm.chain_name">
            </div>
          </div>
          <div class="error">{{ FailForm.chain_id }}</div>
        </li>
        <li class="list-item" v-if="modeInGoods">
          <img class="require" src="../assets/img/icon_require.png" alt>
          <div class="list-item-c">
            <div class="label">类型</div>
            <div class="content" @click.stop="selectTokenType">
              <p>{{confirmForm.token_type | token_type}}</p>
              <img class="chain_name_img" src="../assets/img/icon_back.png" alt>
            </div>
          </div>
          <div class="error">{{ FailForm.token_type }}</div>
        </li>
        <li class="list-item">
          <img class="require" src="../assets/img/icon_require.png" alt>
          <div class="list-item-c">
            <div class="label">Token简称</div>
            <div class="content">
              <input
                type="text"
                @input="limitEnInputSymbol"
                :placeholder="`请输入大写英文和数字（${SYMBOL_LIMIT}至16个字）`"
                v-model="confirmForm.symbol"
                maxlength="16"
                :disabled="actionADD"
              >
            </div>
          </div>
          <div class="error">{{ FailForm.symbol}}</div>
        </li>
        <li class="list-item">
          <img class="require" src="../assets/img/icon_require.png" alt>
          <div class="list-item-c">
            <div class="label">Token全称</div>
            <div class="content">
              <van-field
                v-model="confirmForm.name"
                type="textarea"
                maxlength="40"
                :placeholder="`请输入token全称（${NAME_LIMIT}至40字）`"
                autosize
                :border="false"
                :disabled="actionADD"
                rows="1"
              ></van-field>
            </div>
          </div>
          <div class="error">{{ FailForm.name}}</div>
        </li>
        <li class="list-item no-require" v-if="modeInGoods">
          <div class="list-item-c">
            <div class="label">Token中文名</div>
            <div class="content">
              <input
                type="text"
                @input="limitChinese"
                placeholder="请输入中文名称（限10字）"
                v-model="confirmForm.nickname"
                maxlength="10"
                :disabled="actionADD"
              >
            </div>
          </div>
          <div class="error">{{ FailForm.nickname}}</div>
        </li>
        <li class="list-item">
          <img class="require" src="../assets/img/icon_require.png" alt>
          <div class="list-item-c">
            <div class="label">发行数量</div>
            <div class="content">
              <input type="text" placeholder="最大发行量 900亿 (单位为万)" v-model="confirmForm.total">
              <span>万</span>
            </div>
          </div>
          <div class="error">{{ FailForm.total}}</div>
        </li>
        <li class="list-item">
          <img class="require" src="../assets/img/icon_require.png" alt>
          <div class="list-item-c">
            <div class="label">接收地址</div>
            <div class="content">
              <input
                type="text"
                placeholder="请输入正确地址 （限34位）"
                v-model="computedOwner"
                maxlength="34"
                disabled
              >
            </div>
          </div>
          <div class="error">{{ FailForm.owner}}</div>
        </li>
        <li class="list-item">
          <img class="require" src="../assets/img/icon_require.png" alt>
          <div class="list-item-c">
            <div class="label">Token简介</div>
            <div class="content">
              <van-field
                v-model="confirmForm.introduction"
                type="textarea"
                :maxlength="INTRODUCTION_LIMIT"
                :placeholder="`请输入Token简介（${INTRODUCTION_LIMIT}字以内）`"
                autosize
                :border="false"
                :disabled="actionADD"
                rows="1"
                @input="limitEmjoTextarea"
              ></van-field>
            </div>
          </div>
          <div class="error">{{ FailForm.introduction}}</div>
        </li>
        <li class="list-item">
          <img class="require" src="../assets/img/icon_require.png" alt>
          <div class="list-item-c">
            <div class="label">是否增发</div>
            <div class="content">
              <van-switch
                v-model="category"
                active-color="#FF7E03"
                inactive-color="#52556D"
                size="25px"
                :disabled="actionADD"
              />
            </div>
          </div>
        </li>
        <div class="tip" v-if="!modeInGoods">
          <p>
            发行费
            <span>{{confirmForm.issue_charge || 0}}{{confirmForm.charge_unit}}</span>
          </p>
          <p>
            余额
            <span>{{balance}} {{confirmForm.charge_unit}}</span>
          </p>
        </div>
      </ul>
    </div>
    <!-- 提交-->
    <button
      :class="{ 'commit': true ,'disabled':commitDisabled}"
      @click="handleCommit"
      :disabled="commitDisabled"
    >提交申请</button>

    <!-- 类型选择-->
    <TypeSelect
      v-if="modeInGoods"
      v-model="confirmForm.token_type"
      :visible.sync="typeSelectVisible"
      @confirm="typeSelectVisible = false"
    ></TypeSelect>

    <!--提交等待-->
    <CommitWait :visible.sync="commitWaitVisible" @confirm="commitWaitVisible = false"></CommitWait>
  </div>
</template>

<script lang="ts">
import { Component, Model, Vue, Watch } from "vue-property-decorator";
import MyHeader from "@/components/MyHeader.vue";
import TypeSelect from "@/components/TypeSelect.vue";
import CommitWait from "@/components/CommitWait.vue";
import { ConfirmForm, FailForm } from "@/types/form";
import {
  getBalance,
  CreateRawTokenPreCreateTx,
  setCreateRawTokenMintTx,
  setSendRawTransaction,
  setFeeCreateRawTransaction,
  ApplyConfirm,
  getApplyDetail,
  getValidate,
  getParaList,
  setChain33SendRawTransaction,
  setBTYCreateRawTransaction,
  queryBTYTransaction
} from "@/api/api";
import {
  BASENUMBER,
  NOEXIST,
  MODE,
  MODE_OPTIONS,
  SYMBOL_LIMIT,
  NAME_LIMIT,
  INTRODUCTION_LIMIT
} from "@/types/constant";
import {
  getCurrentBTYAddress,
  signTxGroup,
  configPrivCache
} from "@33cn/wallet-api";

@Component({
  components: {
    MyHeader,
    TypeSelect,
    CommitWait
  }
})
export default class Home extends Vue {
  // 引用初始化
  private confirmForm: any = new ConfirmForm();
  private FailForm: any = new FailForm();
  private routerTostatus: any = (this as any).routerTostatus;
  private SYMBOL_LIMIT: number = SYMBOL_LIMIT;
  private NAME_LIMIT: number = NAME_LIMIT;
  private INTRODUCTION_LIMIT: number = INTRODUCTION_LIMIT;
  // 变量定义
  private typeSelectVisible: Boolean = false;
  private commitWaitVisible: Boolean = false;
  private category: Boolean = true;
  private timer: any = null;
  private balance: number = 0;
  private commitDisabled: Boolean = false;
  private actionADD: Boolean = false;
  private sendParam = {
    id: "",
    pre_create_tx: "",
    pre_send_transaction: ""
  };
  private Validate = {
    name: "",
    symbol: "",
    total: "",
    owner: "",
    introduction: "",
    category: 0,
    chain_id: "",
    charge_unit: "0",
    type: 0,
    nickname: "",
    token_type: ""
  };

  public created() {
    this.handleInit();
  }

  public destroyed() {
    clearTimeout(this.timer);
    this.timer = null;
  }

  // 初始化
  public handleInit() {
    // 设置是否增发按钮显示
    if (
      Object.keys(this.$route.query).length != 0 &&
      Object.assign(this.confirmForm, this.$route.query)
    ) {
      this.category = Boolean(this.confirmForm.category);
    }

    // 设置手续费
    if (
      Object.keys(this.$route.query).length != 0 &&
      this.$route.query.action == "add"
    ) {
      this.actionADD = true;
    }
    getCurrentBTYAddress()
      .then((res: any) => {
        this.confirmForm.owner = res || "";
        console.log('地址',res);
        
        if (res == "") {
          return this.$notify("获取地址失败");
        }
      })
      .then(() => {
        // 获取平行链数据
        return getParaList().then((res: any) => {
          const result = res[0];
          this.confirmForm.chain_id = result.chain_id;
          this.confirmForm.chain_name = result.chain_name;
          this.confirmForm.charge_unit = result.charge_unit;
          this.$route.query.action == "add"
            ? (this.confirmForm.issue_charge = 0)
            : (this.confirmForm.issue_charge = result.issue_charge);
          this.confirmForm.tokens = result.tokens;
          this.confirmForm.exer = result.exer;
        });
      })
      .then(() => {
        // 发币模式下需要获取余额
        if (!this.modeInGoods) {
          return this.getbanlance();
        }
      })
      .catch((err: any) => {
        this.$notify(err);
      });
  }

  // 提交
  public handleCommit(): void {
    console.log("提交", { ...this.confirmForm });
    // 提交清除错误记录
    this.FailForm.reset();
    // 更新一遍余额
    !this.modeInGoods ? this.getbanlance() : "";
    // 为空验证
    const pass = this.Verification();
    if (!pass) {
      return;
    }
    this.commitWaitVisible = true;
    // 整理预校验数据
    this.listAssign(this.Validate, this.confirmForm);
    // 后台校验
    getValidate(this.Validate)
      .then(() => {})
      .then(() => {
        console.log("缓存");
        // 缓存App 私钥
        return configPrivCache(1);
      })
      .then(() => {
        // 直接发币(1.手续费增发,2.发行费用为0,3.发币流程为goods)
        if (
          this.actionADD ||
          this.confirmForm.issue_charge === 0 ||
          this.modeInGoods
        ) {
          this.handleApplyToken(this.confirmForm);
        } else {
          this.$dialog
            .confirm({
              title: "提示",
              message: `发行后将会扣除${this.confirmForm.issue_charge}${
                this.confirmForm.charge_unit
              }手续费，发行失败手续费也不会退回，确认发行吗？`
            })
            .then(() => {
              this.confirmForm.charge_unit == "BTY"
                ? this.handleBTYFee(this.confirmForm)
                : this.handleApplyToken(this.confirmForm);
            })
            .catch(() => {
              this.$notify("取消申请");
              this.commitWaitVisible = false;
              return;
            });
        }
      })
      .catch((error: any) => {
        if (error.msg) {
          for (const errItem in error.msg) {
            this.FailForm[errItem] = error.msg[errItem][0];
          }
        } else {
          this.$notify(error);
        }
        this.commitWaitVisible = false;
      });
  }

  // 手续费为 主代币 / token 代币 发币流程
  public handleApplyToken(confirmObj: ConfirmForm) {
    // 传给App的交易组 用，区分两个
    let signGroup: string = "";
    // 设置方法
    const Chain33setCreateRawTransaction = this.actionADD
      ? setCreateRawTokenMintTx
      : CreateRawTokenPreCreateTx;
    Chain33setCreateRawTransaction(confirmObj)
      .then((res: any) => {
        signGroup = signGroup + res;
      })
      .then(() => {
        // 手续费构造 （手续费为bty，增发，发币模式为goods跳过此步骤）
        if (
          this.actionADD ||
          Number(confirmObj.issue_charge) === 0 ||
          confirmObj.charge_unit == "BTY" ||
          this.modeInGoods
        ) {
          return Promise.resolve();
        }
        const fee = Number(this.confirmForm.issue_charge);
        return setFeeCreateRawTransaction(
          this.confirmForm.charge_unit,
          fee,
          this.confirmForm.exer,
          this.confirmForm.tokens
        ).then((res: any) => {
          signGroup = signGroup + "," + res;
          return Promise.resolve();
        });
      })
      .then(() => {
        const exec = this.confirmForm.exer;
        // APP签名
        return signTxGroup(signGroup, exec, 1).then((res: any) => {
          this.sendParam.pre_create_tx = res;
        });
      })
      .then(() => {
        // 发送交易
        return setSendRawTransaction(this.sendParam.pre_create_tx).then(
          (transactionHash: any) => {
            this.sendParam.pre_send_transaction = transactionHash;
          }
        );
      })
      .then(() => {
        // 发送php后台验证信息
        return ApplyConfirm({
          ...this.Validate,
          ...{ pre_create_tx: this.sendParam.pre_create_tx },
          ...{ pre_send_transaction: this.sendParam.pre_send_transaction }
        }).then((id: any) => {
          this.sendParam.id = id;
          this.confirmForm.id = id;
        });
      })
      .then(() => {
        // 设置轮询
        this.setTimerQueryTransaction(this.sendParam.pre_send_transaction);
      })
      .catch((err: any) => {
        this.commitWaitVisible = false;
        if (err.error) {
          this.$notify(err.error);
        } else {
          this.$notify(err);
        }
      });
  }

  // 扣bty作为手续费
  public handleBTYFee(param: any) {
    setBTYCreateRawTransaction(param)
      .then((res: any) => {
        return Promise.resolve(res);
      })
      .then((beforeSign: string) => {
        return signTxGroup(beforeSign, "none", 1).then((sign: any) => {
          return Promise.resolve(sign);
        });
      })
      .then((sign: string) => {
        return setChain33SendRawTransaction(sign).then((hash: any) => {
          return Promise.resolve(hash);
        });
      })
      .then((hash: string) => {
        // 成功之后查询
        this.setTimerQueryBTYTransactionGrounp(hash);
      })
      .catch((err: any) => {
        this.$notify("BTY扣费失败," + err);
        this.commitWaitVisible = false;
      });
  }

  // 轮询查询主链交易组是否成功
  public setTimerQueryBTYTransactionGrounp(hash: string) {
    let currentHash = hash;
    queryBTYTransaction(currentHash)
      .then((res: any) => {
        // 交易不成功继续轮询
        if (res.actionName === "unknown" && res.tx.next) {
          currentHash = res.tx.next;
          this.setTimerQueryBTYTransactionGrounp(currentHash);
        } else if (res.receipt.ty === 2 && res.tx.next) {
          currentHash = res.tx.next;
          this.setTimerQueryBTYTransactionGrounp(currentHash);
        } else if (res.receipt.ty === 1) {
          this.commitWaitVisible = false;
          this.$notify("BTY扣费查询结果失败");
          clearTimeout(this.timer);
        } else {
          this.handleApplyToken(this.confirmForm);
          clearTimeout(this.timer);
        }
      })
      .catch((error: any) => {
        // 不存在交易继续轮询
        if (error == NOEXIST) {
          this.timer = setTimeout(() => {
            this.setTimerQueryBTYTransactionGrounp(currentHash);
          }, 2000);
        } else {
          this.$notify(error);
          clearTimeout(this.timer);
          this.commitWaitVisible = false;
        }
      });
  }

  // 轮询查询区块链交易是否成功
  public setTimerQueryTransaction(transactionHash: string) {
    const _data = transactionHash;
    getApplyDetail({ id: this.sendParam.id })
      .then((res: any) => {
        // 预发行确认 //预发行成功 //预发行失败
        if (res.status == 1 || res.status == 8 || res.status == 9) {
          this.commitWaitVisible = false;
          clearTimeout(this.timer);
          this.routerTostatus(res.status, this.confirmForm.id);
        } else {
          this.timer = setTimeout(() => {
            this.setTimerQueryTransaction(_data);
          }, 5000);
        }
      })
      .catch((error: any) => {
        this.$notify(error);
      });
  }

  // 获取余额
  public getbanlance() {
    console.log(this.confirmForm,'confirm');
    
    getBalance(this.confirmForm.owner, this.confirmForm.charge_unit)
      .then((res: any) => {
        this.balance = res[0].balance / 1e8;
      })
      .catch((err: any) => {
        this.$notify(err.msg);
      });
  }

  // 校验
  public Verification(): boolean {
    let tag = true;
    // 不为空
    for (const item in this.confirmForm) {
      if ("charge_unit" == item) {
        continue;
      }
      if ("id" == item) {
        continue;
      }
      if ("charge_unit" == item) {
        continue;
      }
      if ("issue_charge" == item) {
        continue;
      }
      if ("nickname" == item) {
        continue;
      }
      if ("origin" == item) {
        continue;
      }
      if ("template" == item) {
        continue;
      }
      if ("token_type" == item && !this.modeInGoods) {
        continue;
      }
      if (
        this.confirmForm[item] === null ||
        this.confirmForm[item] === undefined ||
        this.confirmForm[item] === ""
      ) {
        this.FailForm[item] = "该项不能为空";
        tag = false;
        this.$notify(`${item}验证未通过,请检查后重新申请`);
      }
    }
    // 发行费 小于 余额
    if (
      this.confirmForm.issue_charge > this.balance &&
      !this.actionADD &&
      !this.modeInGoods
    ) {
      tag = false;
      this.$notify("余额不足");
    }
    // 判断简称字母大写
    if (!/^[A-Z1-9]+$/.test(this.confirmForm.symbol)) {
      tag = false;
      this.FailForm.symbol = "必须为大写字母或数字1-9";
    }
    // 判断简称位数不小于6位
    if (this.confirmForm.symbol.length < this.SYMBOL_LIMIT) {
      tag = false;
      this.FailForm.symbol = `简称至少${this.SYMBOL_LIMIT}位`;
    }

    // 判断全称位数不小于3位
    if (this.confirmForm.name.length < this.NAME_LIMIT) {
      tag = false;
      this.FailForm.name = `全称不能小于${this.NAME_LIMIT}位`;
    }

    // 增发得时候必须小于10亿
    if (this.actionADD && this.confirmForm.total > 9 * 1e8) {
      tag = false;
      this.FailForm.total = "增发单次必须小于10亿";
    }
    return tag;
  }

  // 复制对象
  public listAssign(arrA: any, arrB: any): any {
    const type = this.actionADD ? 1 : 0;
    arrB.type = type;
    return Object.keys(arrA).forEach(key => {
      arrA[key] = arrB[key];
    });
  }

  // 查看记录
  public queryRecord(): void {
    this.$router.push({
      path: "/record"
    });
  }

  // 选择平行链
  public selectTokenType(): void {
    if (!this.actionADD) {
      this.typeSelectVisible = true;
    }
  }

  // 简介限制数字英文字符输入
  public limitEnInputSymbol(e: any) {
    const value = e.target.value;
    const regex = /[^a-zA-Z1-9]/g;
    if (regex.test(value)) {
      this.confirmForm.symbol = "";
      return;
    }
    this.confirmForm.symbol = e.target.value.toUpperCase();
  }

  // 限制文本框不输入表情
  public limitEmjoTextarea() {
    this.confirmForm.introduction = this.confirmForm.introduction.replace(
      /\uD83C[\uDF00-\uDFFF]|\uD83D[\uDC00-\uDE4F]/g,
      ""
    );
  }

  // 限值token中文输入
  public limitChinese(e: any) {
    const value = e.target.value;
    const regex = /^[\u0391-\uFFE5]+$/;
    if (!regex.test(value)) {
      this.confirmForm.nickname = "";
      return;
    }
  }

  // 是否增发
  @Watch("category")
  public onCategoryChanged(val: string) {
    if (val) {
      this.confirmForm.category = 1;
    } else {
      this.confirmForm.category = 0;
    }
  }

  // 限制数字输入
  @Watch("confirmForm.total")
  public limitTotalChanged(newVal: any, oldVal: any) {
    const regex = /^([0-9]*[1-9][0-9]*(.[0-9]+)?|[0]+.[0-9]*[1-9][0-9]*)$/;
    if (!regex.test(newVal)) {
      if (newVal.toString().indexOf(".") != -1) {
        this.confirmForm.total = oldVal;
      } else {
        this.confirmForm.total = "";
      }
      return;
    }
    if (newVal < 0) {
      // 如果小于等于零
      this.confirmForm.total = 0;
      return;
    }
    if (newVal > 900 * BASENUMBER) {
      this.confirmForm.total = 900 * BASENUMBER;
      return;
    }
    this.confirmForm.total = newVal;
  }

  // 控制提交按钮显示
  @Watch("confirmForm", { deep: true })
  public onButttonShow(newVal: any, oldVal: any) {
    // 控制提交按钮禁用
    this.commitDisabled = !this.confirmForm.checkRequire();
  }

  // 地址显示
  get computedOwner() {
    const detail = this.confirmForm;
    if (!detail.owner) {
      return "";
    }
    if (detail.owner.length < 12) {
      return detail.owner;
    }
    const targetStr = detail.owner;
    const star = targetStr.slice(0, 8);
    const end = targetStr.slice(targetStr.length - 4, targetStr.length);
    return `${star}...${end}`;
  }

  // 发行模式
  get modeInGoods() {
    return MODE === MODE_OPTIONS.GOODS;
  }
}
</script>
<style scoped lang="scss">
.home {
  min-height: 100vh;
}

.top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 19px;

  h1 {
    font-size: 30px;
    margin: 40px 0 40px 0;
  }

  img {
    width: 17px;
    height: 17px;
    margin-right: 3px;
  }

  &-button {
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 7px 10px;
    margin: 40px 0 40px 0;
    border-radius: 15px;
    background-color: #7190ff;
    color: #ffffff;
  }
}

.center {
  ul {
    li {
      display: flex;
      flex-direction: row;
      flex-wrap: wrap;
      justify-content: flex-start;
      width: 375px;

      .error {
        width: 100%;
        text-align: right;
        color: #f29049;
        margin: 3px 21px 0 21px;
      }

      .require {
        display: inline-block;
        width: 10px;
        height: 10px;
        align-self: center;
        margin: 3px 0 8px 8px;
      }
    }
  }

  .no-require {
    margin: 0 21px 0 21px !important;
  }

  .list-item-c {
    width: calc(100% - 42px);
    margin: 0 21px 0 2px;
    display: flex;
    position: relative;
    justify-content: flex-start;
    align-items: center;
    flex-wrap: wrap;
    padding-bottom: 5px;

    &:after {
      @include onePxBottom;
      background-color: #9599a4;
    }

    .label {
      width: 30%;
      font-size: 14px;
    }

    .content {
      display: flex;
      align-items: center;
      justify-content: flex-end;
      width: 70%;

      input {
        width: 100%;
        min-height: 20px;
        background-color: rgba(0, 0, 0, 0);
        border: none;
        font-size: 14px;
        margin: 0;
        padding: 0;
        flex-grow: 1;
        text-align: right;

        @include placeholder {
          color: #9599a4 !important;
          font-size: 14px;
        }
      }

      span {
        margin-left: 5px;
      }
    }
  }

  .chain_name_img {
    width: 7px;
    height: 14px;
    transform: rotate(180deg);
    margin-left: 10px;
  }

  .tip {
    display: flex;
    justify-content: space-between;
    padding: 5px 21px;

    p {
      padding: 0;
      margin: 0;
      color: #f29049;
    }

    span {
      color: #ffffff;
      margin-left: 5px;
    }
  }

  .error {
    min-height: 20px;
  }
}

.commit {
  position: relative;
  width: 310px;
  left: 50%;
  margin: 60px 0 60px -155px;
  height: 44px;
  background-color: #7190ff;
  border-radius: 29px;

  &:active {
    background-color: #5e6377 !important;
  }
}

.disabled {
  background-color: #5e6377 !important;
}

input {
  &:disabled,
  &[disabled] {
    color: #fff !important;
    -webkit-opacity: 1;
    opacity: 1;
  }
}
</style>
<style lang="scss">
.home {
  .van-cell {
    padding: 0;
  }

  textarea {
    &:disabled,
    &[disabled] {
      -webkit-text-fill-color: #ffffff; //是用来做填充色使用的
      -webkit-opacity: 1;
      color: #ffffff;
    }
  }
}
</style>

